package com.ctgu.tengyun.util;

import org.apache.commons.codec.binary.Base64;

public class MixedEncryption {
	
	public static Long KEY = 0L;
	
	public static String encode(String secretKey, Object ...objs){
		char[] allchs = getAllChars(objs);
		char[] encryptChs = encrypt(allchs, secretKey);
		byte[] bss = new byte[encryptChs.length];
		for( int i =0; i<encryptChs.length; i++  ) {
			bss[i] = char2byte(encryptChs[i]);
		}
		byte[] bs = Base64.encodeBase64(bss);
		
		String newencrypt = new String(bs);
		newencrypt = replace(newencrypt);
		
		return newencrypt;
	}

	public static String[] decode(String encodeStr, String secretKey){
		String str = revertReplace(encodeStr);
		byte[] bs = Base64.decodeBase64(str.getBytes());
		char[] allchs = new char[bs.length];
		for( int i=0; i< bs.length; i++ ) {
			allchs[i] = byte2char(bs[i]);
		}
		char[] decyptChs = decypt2(allchs, secretKey);
		return new String(decyptChs).split("\\|");
	}

	private static char[] getAllChars(Object ...objs) {
		StringBuilder sb = new StringBuilder();
		for( Object obj : objs ) {
			sb.append(String.valueOf(obj)).append("|");
		}
		return sb.toString().toCharArray();
	}
	
	private static String replace(String str){
		String returnStr = "";
		
		char[] chars = str.toCharArray();
		for (char c : chars) {
			if('i' == c){
				returnStr += "ia";
			} else if('+' == c){
				returnStr += "ib";
			} else if('/' == c){
				returnStr += "ic";
			} else if('=' == c){
				returnStr += "id";
				continue;
			} else {
				returnStr += c;
			} 
		}
		
		return returnStr;
	}
	
	private static String revertReplace(String str){
		String returnStr = str;
		
		returnStr = returnStr.replaceAll("ic", "/");
		returnStr = returnStr.replaceAll("ib", "+");
		returnStr = returnStr.replaceAll("id", "=");
		returnStr = returnStr.replaceAll("ia", "i");	
		return returnStr;
	}
	    
	private static char[] encrypt(char[] sourceStr, String secretKey){
		int lenStr = sourceStr.length;
		int lenKey = secretKey.length();
		
		char[] result = new char[lenStr];
		
		result[0]  = sourceStr[0];
		
		char[] keyChs = secretKey.toCharArray();
		byte[] bs = new byte[lenStr];
		for(int i = 0 ; i<lenStr; ++i){
			bs[i] = char2byte(sourceStr[i]);
		}
		
		for(int i = 1; i< lenStr; ++i){
			int it = (int)((bs[i])^(bs[i-1])) +  (int)(char2byte(keyChs[i%lenKey]));
			bs[i] = (byte)it;
			result[i] += byte2char(bs[i]);
		}
	
		return result;	
	}
	
	private static char[] decypt2(char[] sourceStr, String secretKey){
		int lenStr = sourceStr.length;
		int lenKey = secretKey.length();
		
		char[] result = new char[lenStr];
		
		result[0]  = sourceStr[0];
		
		char[] keyChs = secretKey.toCharArray();
		byte[] bs = new byte[lenStr];
		for(int i = 0 ; i<lenStr; ++i){
			bs[i] = char2byte(sourceStr[i]);
		}
		for(int i = lenStr - 1; i > 0; i--){
			int it = (unsignedbyte(bs[i])-unsignedbyte(char2byte(keyChs[i%lenKey])) ) ^ unsignedbyte(bs[i-1]);
			bs[i] = (byte)it;
			result[i] = byte2char(bs[i]);
		}
		result[0]  = byte2char(bs[0]);
		return result;
	}
	
	private static byte char2byte(char c){
		return unpackc(c);
	}
	
	
	private static char byte2char(byte b){
		return packc(b);
	}

	private static char packc(byte b){
		return (char)b;
	}
	
	private static byte unpackc(char c){
		return (byte)c;
	}
	
	private static int unsignedbyte(byte b){
		return (int)(b) < 0 ? (int)b + 256 : (int) b;
	}
	
}
